package nl.harmidi.swing;

import java.awt.Component;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.Timer;

import nl.harmidi.harmonictable.EmptySpot;
import nl.harmidi.harmonictable.Spot;
import nl.harmidi.harmonictable.TableModel;

import org.grlea.log.SimpleLogger;

public class TablePanel extends JPanel {
	private static final int MAGICAL_HEXAGON_RADIUS_Y_DIVIDER = 19;

	private static final int MAGICAL_HEXAGON_RADIUS_X_DIVIDER = 26;

	private static final long serialVersionUID = 1L;

	private static final SimpleLogger log = new SimpleLogger(TablePanel.class);

	private final List<Hexagon> hexagons = new ArrayList<Hexagon>();

	private final TableModel tableModel;

	private int leftMargin;

	private int topMargin;

	private int hexagonRadius;

	private final Timer repaintTimer;

	public TablePanel(final TableModel tableModel) {
		this.tableModel = tableModel;

		repaintTimer = new Timer(100, new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				repaint();
			}
		});

		addComponentListener(new ComponentAdapter() {
			@Override
			public void componentResized(ComponentEvent e) {
				createHexagons();
			}
		});
	}

	private void createHexagons() {
		repaintTimer.stop();
		recalculateCoordinateSystem();
		log.debugObject("Hexagon radius", hexagonRadius);
		hexagons.clear();
		for (Spot spot : tableModel.getAllSpots()) {
			if (!(spot instanceof EmptySpot)) {
				int x = getXfor(spot);
				int y = getYfor(spot);
				hexagons.add(new Hexagon(x, y, spot, hexagonRadius));
			}
		}
		repaintTimer.start();
	}

	private void recalculateCoordinateSystem() {
		final int hexagonRadiusX = getWidth() / MAGICAL_HEXAGON_RADIUS_X_DIVIDER;
		final int hexagonRadiusY = getHeight() / MAGICAL_HEXAGON_RADIUS_Y_DIVIDER;
		if (hexagonRadiusX < hexagonRadiusY) {
			hexagonRadius = hexagonRadiusX;
			leftMargin = 0;
			topMargin = (getHeight() - (MAGICAL_HEXAGON_RADIUS_Y_DIVIDER * hexagonRadiusX)) / 2;
		} else {
			hexagonRadius = hexagonRadiusY;
			leftMargin = (getWidth() - (MAGICAL_HEXAGON_RADIUS_X_DIVIDER * hexagonRadiusY)) / 2;
			topMargin = 0;
		}
	}

	@Override
	protected void paintComponent(Graphics g) {
		super.paintComponent(g);

		// anti-aliasing is too slow :(
		// ((Graphics2D) g).setRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));

		 for (Hexagon hexagon : hexagons) {
			hexagon.paintComponent(g);
		}
	}

	private int getXfor(Spot spot) {
		int rowWidth = spot.getRowNumber() % 2 == 0 ? 9 : 8;
		int columnNr = spot.getColumnNumber();

		if (rowWidth == 9) {
			return leftMargin + ((((columnNr - 1) * 3) + 1) * hexagonRadius);
		} else {
			return leftMargin + ((int) Math.round((((columnNr - 1) * 3) + 2.5D) * hexagonRadius));
		}
	}

	private int getYfor(Spot spot) {
		return topMargin + spot.getRowNumber() * ((int) (hexagonRadius - (hexagonRadius / 6)));
	}

}
